/*-*
 * FILENAME  :
 *    $HeadURL$
 *
 * STATUS  :
 *    $Revision$
 *
 *    $Author$
 *    $Date$
 *  
 *    
 * Copyright (c) 2011 Gonalge Ltda. All rights reserved.
 *
 ****************************************************************/

package org.gonalge.rompecabeza.cliente;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.JTextPane;
import javax.swing.UIManager;

import java.awt.BorderLayout;
import java.awt.Cursor;
import java.awt.Font;
import java.awt.List;
import java.awt.ScrollPane;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.util.Vector;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.gonalge.rompecabeza.dto.Conexion;
import org.gonalge.rompecabeza.dto.Jugador;
import org.gonalge.rompecabeza.dto.Mensaje;
import org.gonalge.rompecabeza.negocio.Juego;
import org.gonalge.rompecabeza.negocio.ListaPieza;
import org.gonalge.rompecabeza.pintado.PintarCliente;
import org.gonalge.rompecabeza.remoto.ClienteRemoto;
import org.gonalge.rompecabeza.remoto.ServidorRemoto;
import org.gonalge.rompecabeza.remoto.imp.Notificador;
import org.gonalge.rompecabeza.util.FormConexion;
import org.gonalge.rompecabeza.util.FormUtils;

/**
 * 
 * @author Geremias Gonzalez
 */
public class FormCliente extends JFrame implements ClienteRemoto, ActionListener, KeyListener, MouseListener, MouseMotionListener {
    /**
     * 
     */
    private static final long serialVersionUID = 1938066477590654006L;

    private static final Log LOG = LogFactory.getLog(FormCliente.class);

    private final Conexion conexion = new Conexion();

    private final PintarCliente pintado = new PintarCliente();

    private final JPanel opciones = new JPanel(new BorderLayout());

    private final JSplitPane separadorMensaje = new JSplitPane(0);

    private final JTextPane enviarSMS = new JTextPane();

    private final JTextPane recibirSMS = new JTextPane();

    private final JButton enviar = new JButton("ENVIAR");;

    private final JButton conectar = new JButton("CONECTAR");

    private final List listaUsuario = new List();

    private boolean buttonDerecho = true;

    private ServidorRemoto servidorRemoto = null;

    private Juego juego = null;

    public FormCliente() {
        try {
            jbInit();
        } catch (Exception e) {
            LOG.error("General ", e);
        }
    }

    private void jbInit() throws Exception {

        this.getContentPane().setLayout(null);
        this.setDefaultCloseOperation(0);
        this.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                avandonarJuego();
            }
        });
        addObjetos();
        addEventos();

    }

    private void addObjetos() {
        this.setResizable(false);
        this.setBounds(FormUtils.centarRectangle(1025, 740));
        this.setTitle("DESCONECTADO");
        enviar.setToolTipText("ENVIAR");
        opciones.setSize(100, getHeight());

        opciones.add(conectar, BorderLayout.NORTH);
        opciones.add(listaUsuario, BorderLayout.CENTER);

        separadorMensaje.setBounds(opciones.getWidth(), getHeight() - 200, getWidth() - opciones.getWidth(), 160);
        pintado.setBounds(opciones.getWidth(), 0, getWidth() - opciones.getWidth(), getHeight() - 200);

        ScrollPane scrollPane = new ScrollPane();
        recibirSMS.setEditable(false);
        recibirSMS.setFont(new Font("Arial", 1, 15));
        scrollPane.add(recibirSMS);
        separadorMensaje.add(scrollPane);

        enviar.setCursor(new Cursor(Cursor.HAND_CURSOR));
        conectar.setCursor(new Cursor(Cursor.HAND_CURSOR));

        JPanel panelAux = new JPanel(new BorderLayout());

        ScrollPane scrollPane1 = new ScrollPane();
        enviarSMS.setFont(new Font("Arial", 1, 15));
        scrollPane1.add(enviarSMS);

        panelAux.add(enviar, BorderLayout.WEST);
        panelAux.add(scrollPane1, BorderLayout.CENTER);
        separadorMensaje.add(panelAux);

        this.getContentPane().add(opciones, BorderLayout.EAST);
        this.getContentPane().add(pintado, BorderLayout.CENTER);
        this.getContentPane().add(separadorMensaje, BorderLayout.SOUTH);
        setVisible(true);

    }

    private void addEventos() {
        conectar.addActionListener(this);
        enviar.addActionListener(this);
        enviarSMS.addKeyListener(this);
        pintado.addMouseListener(this);
        pintado.addMouseMotionListener(this);
    }

    private void avandonarJuego() {
        if (JOptionPane.showConfirmDialog(new JFrame(), "Desea Salir del Juego", "OPCIONES DE JUEGO", 2, 2) == 0) {
            if (servidorRemoto != null)
                eventoDesconectado();
            System.exit(0);
        }
    }

    // *******EVENTOS*****
    @Override
    public void actionPerformed(ActionEvent e) {
        if (e.getSource().equals(conectar)) {
            if (servidorRemoto == null)
                eventoConexion();
            else {
                if (JOptionPane.showConfirmDialog(new JFrame(), "Desea Salir del Juego", "OPCIONES DE JUEGO", 2, 2) == 0)
                    eventoDesconectado();
            }
        }
        if (e.getSource().equals(enviar)) {
            enviarMensaje();
        }
    }

    @Override
    public void keyTyped(KeyEvent e) {
    }

    @Override
    public void keyPressed(KeyEvent e) {

    }

    @Override
    public void keyReleased(KeyEvent e) {
        if (e.getKeyCode() == KeyEvent.VK_ENTER) {
            enviarMensaje();
        }
    }

    @Override
    public void mouseClicked(MouseEvent e) {
    }

    @Override
    public void mousePressed(MouseEvent e) {
        if (juego != null) {
            if (e.getButton() == MouseEvent.BUTTON1) { // Boton derecho
                buttonDerecho = true;
                try {
                    servidorRemoto.seleccionarPieza(conexion.getUsuario(), e.getX(), e.getY());
                } catch (RemoteException ex) {
                    LOG.error("Seleccionar pieza", ex);
                }
            } else {
                buttonDerecho = false;
                pintado.cargarXY(e.getX(), e.getY());
            }
        }
    }

    @Override
    public void mouseReleased(MouseEvent e) {
        if (juego != null) {
            pintado.cargarXY(-1, -1);
            try {
                servidorRemoto.soltarPieza(conexion.getUsuario());
            } catch (RemoteException ex) {
                LOG.error("Soltar pieza", ex);
            }
        }
    }

    @Override
    public void mouseEntered(MouseEvent e) {
    }

    @Override
    public void mouseExited(MouseEvent e) {
    }

    @Override
    public void mouseDragged(MouseEvent e) {
        if (juego != null) {
            if (buttonDerecho) { // Boton derecho
                try {
                    servidorRemoto.moverPieza(conexion.getUsuario(), e.getX(), e.getY());
                } catch (RemoteException ex) {
                    LOG.error("Mover pieza", ex);
                }
            } else
                pintado.cargarXY(e.getX(), e.getY());
        }
    }

    @Override
    public void mouseMoved(MouseEvent e) {
    }

    // *******************OTROS*METODOS***********************

    public boolean conectar() {
        try {
            servidorRemoto = (ServidorRemoto) Naming.lookup(conexion.getURL());
            Notificador Notifica = new Notificador();
            Notifica.adicionarEscuchador(this);
            return servidorRemoto.conectar(conexion.getUsuario(), Notifica);
        } catch (RemoteException e) {
            LOG.error("RemoteException ", e);
            return false;
        } catch (NotBoundException e) {
            LOG.error("NotBoundException ", e);
            return false;
        } catch (MalformedURLException e) {
            LOG.error("MalformedURLException ", e);
            return false;
        }
    }

    private void eventoConexion() {
        FormConexion formConexion = new FormConexion(true, conexion);
        if (formConexion.isConectar()) {
            if (conectar()) {
                pintado.setNombre(conexion.getUsuario());
                conectar.setText("Desconectar");
                setTitle("Usuario: " + conexion.getUsuario());
            } else {
                servidorRemoto = null;
                this.setTitle("DESCONECTADO");
                JOptionPane.showMessageDialog(new JFrame(), "No puede ser Conectado");
            }
        }
    }

    private void eventoDesconectado() {
        this.setTitle("DESCONECTADO");
        try {
            servidorRemoto.desConectar(conexion.getUsuario());
            listaUsuario.removeAll();
            conectar.setText("Conectar");
            servidorRemoto = null;
            juego = null;
            enviarSMS.setText("");
            recibirSMS.setText("");
            pintado.setJuego(juego);
            pintado.repaint();
        } catch (RemoteException e) {
            LOG.error("RemoteException ", e);
        }
    }

    // *************Metoso*remotos*******************

    @Override
    public void conexionExitosa() {
        LOG.info("Conectado");
    }

    @Override
    public void servicioTerminado() {
        eventoDesconectado();
    }

    @Override
    public void actualizarListaUsuarios(Vector<String> event) {
        listaUsuario.removeAll();
        for (String string : event) {
            listaUsuario.add(string);
        }
    }

    @Override
    public void recibirMensaje(Mensaje event) {
        String Mensaje = event.getUsuario() + ">> " + event.getMsm();
        recibirSMS.setText(recibirSMS.getText().trim() + "\n" + Mensaje);
    }

    @Override
    public void recibirJuego(boolean sw, Juego event) {
        pintado.setNombre(conexion.getUsuario());
        if (!sw || juego == null) {
            juego = event;
            juego.addJugador(new Jugador(conexion.getUsuario()));
        }
        actualizarJuego();
    }

    private void actualizarJuego() {
        int maxAscierto = juego.getMaxAciertos();
        int cantAscierto = juego.getAsciertos(conexion.getUsuario());
        if (juego.finJuego()) {
            Jugador juegoAux = juego.jugadorGanador(maxAscierto);
            pintado.setGanador(cantAscierto == maxAscierto ? "" : "GANADOR ES: " + juegoAux.getNombre().toUpperCase() + " CON " + maxAscierto + " ACIERTOS");
        } else
            pintado.setGanador(cantAscierto == maxAscierto ? "ESTAS GANANDO" : "ESTAS PERDIENTO");
        pintado.setJuego(this.juego);
    }

    @Override
    public void actualizarPiezas(ListaPieza pDes, Vector<Jugador> jug) {
        // Mover Pieza
        this.juego.setPiezaPerdiente(pDes);
        this.juego.setJugadores(jug);
        pintado.repaint();
    }

    @Override
    public void actualizarTablero(ListaPieza pDes, Vector<Jugador> jug, Vector<Byte> esTa) {
        // soltar pieza
        this.juego.setEstadoTablero(esTa);
        this.juego.setPiezaPerdiente(pDes);
        this.juego.setJugadores(jug);
        actualizarJuego();
    }

    private void enviarMensaje() {
        if (servidorRemoto != null && juego != null) {
            if (StringUtils.isNotBlank(enviarSMS.getText())) {
                try {
                    servidorRemoto.enviarMensaje(new Mensaje(conexion.getUsuario(), enviarSMS.getText().trim()));
                    enviarSMS.setText("");
                } catch (RemoteException ex) {
                    LOG.error("Enviar Mensage", ex);
                }
            }
        } else {
            JOptionPane.showMessageDialog(new JFrame(), "Estoy Desconectado");
        }
    }

    public static void main(String[] args) {
        try {
            UIManager.setLookAndFeel("de.muntjak.tinylookandfeel.TinyLookAndFeel");
            new FormCliente().setVisible(true);
        } catch (Exception e) {
            LOG.error("main ", e);
        }
    }
}
